#!/usr/bin/env python3
"""
传感器数据管理模块
用于管理和处理ESP32传感器数据
"""

import time
import json
import threading
from datetime import datetime
from typing import Dict, List, Optional, Callable
from dataclasses import dataclass, asdict
from esp32_comm import ESP32Communicator

@dataclass
class SensorReading:
    """传感器读数数据类"""
    timestamp: float
    temperature: Optional[float] = None
    humidity: Optional[float] = None
    led_state: Optional[bool] = None
    
    def to_dict(self) -> Dict:
        """转换为字典"""
        return asdict(self)
    
    def to_json(self) -> str:
        """转换为JSON字符串"""
        return json.dumps(self.to_dict(), indent=2)

class SensorManager:
    """传感器管理器"""
    
    def __init__(self, esp32_comm: ESP32Communicator, data_callback: Optional[Callable] = None):
        """
        初始化传感器管理器
        
        Args:
            esp32_comm: ESP32通信器实例
            data_callback: 数据回调函数，接收SensorReading参数
        """
        self.esp32 = esp32_comm
        self.data_callback = data_callback
        self.readings_history: List[SensorReading] = []
        self.is_monitoring = False
        self.monitor_thread: Optional[threading.Thread] = None
        self.monitor_interval = 5.0  # 默认5秒采集一次
        
    def read_current_data(self) -> Optional[SensorReading]:
        """读取当前传感器数据"""
        if not self.esp32.is_connected:
            return None
            
        try:
            # 读取所有传感器数据
            sensor_data = self.esp32.read_all_sensors()
            if sensor_data:
                reading = SensorReading(
                    timestamp=time.time(),
                    temperature=sensor_data.get('temp'),
                    humidity=sensor_data.get('humidity')
                )
                
                # 读取LED状态
                led_state = self.esp32.get_gpio_state(2)  # GPIO2是LED
                reading.led_state = led_state
                
                # 添加到历史记录
                self.readings_history.append(reading)
                
                # 限制历史记录数量
                if len(self.readings_history) > 1000:
                    self.readings_history = self.readings_history[-1000:]
                
                # 调用回调函数
                if self.data_callback:
                    self.data_callback(reading)
                
                return reading
            
        except Exception as e:
            print(f"读取传感器数据失败: {e}")
            return None
    
    def start_monitoring(self, interval: float = 5.0):
        """开始监控传感器数据"""
        if self.is_monitoring:
            print("监控已经在运行中")
            return
            
        self.monitor_interval = interval
        self.is_monitoring = True
        self.monitor_thread = threading.Thread(target=self._monitor_loop, daemon=True)
        self.monitor_thread.start()
        print(f"开始监控传感器数据，间隔: {interval}秒")
    
    def stop_monitoring(self):
        """停止监控传感器数据"""
        self.is_monitoring = False
        if self.monitor_thread:
            self.monitor_thread.join()
        print("停止监控传感器数据")
    
    def _monitor_loop(self):
        """监控循环"""
        while self.is_monitoring:
            reading = self.read_current_data()
            if reading:
                print(f"[{datetime.fromtimestamp(reading.timestamp)}] "
                      f"温度: {reading.temperature}°C, "
                      f"湿度: {reading.humidity}%, "
                      f"LED: {'ON' if reading.led_state else 'OFF'}")
            
            time.sleep(self.monitor_interval)
    
    def get_latest_reading(self) -> Optional[SensorReading]:
        """获取最新的传感器读数"""
        if self.readings_history:
            return self.readings_history[-1]
        return None
    
    def get_history(self, count: int = 10) -> List[SensorReading]:
        """获取历史读数"""
        return self.readings_history[-count:]
    
    def get_temperature_trend(self, count: int = 10) -> List[float]:
        """获取温度趋势"""
        recent_readings = self.get_history(count)
        return [r.temperature for r in recent_readings if r.temperature is not None]
    
    def get_humidity_trend(self, count: int = 10) -> List[float]:
        """获取湿度趋势"""
        recent_readings = self.get_history(count)
        return [r.humidity for r in recent_readings if r.humidity is not None]
    
    def get_statistics(self) -> Dict:
        """获取统计信息"""
        if not self.readings_history:
            return {}
        
        temps = [r.temperature for r in self.readings_history if r.temperature is not None]
        humidities = [r.humidity for r in self.readings_history if r.humidity is not None]
        
        stats = {
            "total_readings": len(self.readings_history),
            "time_range": {
                "start": datetime.fromtimestamp(self.readings_history[0].timestamp).isoformat(),
                "end": datetime.fromtimestamp(self.readings_history[-1].timestamp).isoformat()
            }
        }
        
        if temps:
            stats["temperature"] = {
                "min": min(temps),
                "max": max(temps),
                "avg": sum(temps) / len(temps),
                "count": len(temps)
            }
        
        if humidities:
            stats["humidity"] = {
                "min": min(humidities),
                "max": max(humidities),
                "avg": sum(humidities) / len(humidities),
                "count": len(humidities)
            }
        
        return stats
    
    def save_data_to_file(self, filename: str):
        """保存数据到文件"""
        try:
            data = {
                "export_time": datetime.now().isoformat(),
                "readings": [reading.to_dict() for reading in self.readings_history],
                "statistics": self.get_statistics()
            }
            
            with open(filename, 'w', encoding='utf-8') as f:
                json.dump(data, f, indent=2, ensure_ascii=False)
            
            print(f"数据已保存到: {filename}")
            
        except Exception as e:
            print(f"保存数据失败: {e}")
    
    def control_led(self, state: bool) -> bool:
        """控制LED"""
        return self.esp32.set_led(state)
    
    def reset_esp32(self) -> bool:
        """重启ESP32"""
        return self.esp32.reset_esp32()

# 使用示例
if __name__ == "__main__":
    # 数据回调函数
    def on_sensor_data(reading: SensorReading):
        print(f"新数据: {reading.to_json()}")
    
    # 创建ESP32通信器
    esp32 = ESP32Communicator('/dev/ttyUSB0')
    
    if esp32.connect():
        # 创建传感器管理器
        sensor_mgr = SensorManager(esp32, on_sensor_data)
        
        try:
            # 读取单次数据
            current = sensor_mgr.read_current_data()
            if current:
                print(f"当前数据: {current.to_json()}")
            
            # 开始监控
            sensor_mgr.start_monitoring(interval=3.0)
            
            # 运行一段时间
            time.sleep(20)
            
            # 控制LED
            print("开启LED...")
            sensor_mgr.control_led(True)
            time.sleep(3)
            
            print("关闭LED...")
            sensor_mgr.control_led(False)
            time.sleep(3)
            
            # 获取统计信息
            stats = sensor_mgr.get_statistics()
            print(f"统计信息: {json.dumps(stats, indent=2, ensure_ascii=False)}")
            
            # 保存数据
            sensor_mgr.save_data_to_file("sensor_data.json")
            
        except KeyboardInterrupt:
            print("用户中断")
        finally:
            # 停止监控
            sensor_mgr.stop_monitoring()
            esp32.disconnect()
    else:
        print("连接ESP32失败") 